package cn.edu.fudan.tools;

import cn.edu.fudan.data.*;
import cn.edu.fudan.type.Config;
import cn.edu.fudan.type.DataItem;
import cn.edu.fudan.type.Feature;
import org.apache.log4j.Logger;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class ClassifierSummary {

	private static Logger logger = Logger.getLogger(ClassifierSummary.class);

	public void classifer(Feature feature, List<List<Long>> trainpoints, List<List<Long>> testpoints)
			throws IOException {
		Config config = new GetConfig().getConfig();
		HandelFeature handelFeature = new HandelFeature();
		SlideWindow slideWindow = new SlideWindow();
		HandleDistance handleDistance = new HandleDistance();

		List<List<DataItem>> data_A = slideWindow.extractWindow(feature.getAbnormal(), trainpoints.get(0),
				config.getWindow_length());
		List<List<DataItem>> data_B = slideWindow.extractWindow(feature.getAbnormal(), trainpoints.get(1),
				config.getWindow_length());

		List<List<DataItem>> test_A = slideWindow.extractWindow(feature.getAbnormal(), testpoints.get(0),
				config.getWindow_length());
		List<List<DataItem>> test_B = slideWindow.extractWindow(feature.getAbnormal(), testpoints.get(1),
				config.getWindow_length());

		List<List<Double>> maps_A = new ArrayList<>();
		List<List<Double>> maps_B = new ArrayList<>();

		List<List<Double>> testmaps_A = new ArrayList<>();
		List<List<Double>> testmaps_B = new ArrayList<>();

		for (int i = 0; i < data_A.size(); i++) {
			List<Double> map = handelFeature.handleFeature(data_A.get(i), config.getN_segment());
			maps_A.add(map);
		}

		for (int i = 0; i < data_B.size(); i++) {
			List<Double> map = handelFeature.handleFeature(data_B.get(i), config.getN_segment());
			maps_B.add(map);
		}

		for (int i = 0; i < test_A.size(); i++) {
			List<Double> map = handelFeature.handleFeature(test_A.get(i), config.getN_segment());
			testmaps_A.add(map);
		}

		for (int i = 0; i < test_B.size(); i++) {
			List<Double> map = handelFeature.handleFeature(test_B.get(i), config.getN_segment());
			testmaps_B.add(map);
		}

		logger.info("Training Phase(Class A)");
		handleDistance.calAccuracy(maps_A, maps_B, maps_A, config.getK());

		logger.info("Training Phase(Class B)");
		handleDistance.calAccuracy(maps_B, maps_A, maps_B, config.getK());

		logger.info("Class A: ");
		handleDistance.calAccuracy(maps_A, maps_B, testmaps_A, config.getK());

		logger.info("Class B: ");
		handleDistance.calAccuracy(maps_B, maps_A, testmaps_B, config.getK());

		print(data_A, data_B, test_A, test_B);

		// for(int i = 0; i < data_A.size(); i ++){
		// FileWriter fWriter = new
		// FileWriter("E:\\Explosion\\dataset\\posi\\"+(i+1));
		// for(DataItem di : data_A.get(i)){
		// fWriter.write(di.getTimestamp()+"\t"+di.getValue()+"\r\n");
		// }
		// fWriter.close();
		// }
		// for(int i = 0; i < data_B.size(); i ++){
		// FileWriter fWriter = new
		// FileWriter("E:\\Explosion\\dataset\\nega\\"+(i+1));
		// for(DataItem di : data_B.get(i)){
		// fWriter.write(di.getTimestamp()+"\t"+di.getValue()+"\r\n");
		// }
		// fWriter.close();
		// }
	}

	public void paaclassifer(Feature feature, List<List<Long>> trainpoints, List<List<Long>> testpoints)
			throws IOException {
		Config config = new GetConfig().getConfig();
		HandelFeature handelFeature = new HandelFeature();
		SlideWindow slideWindow = new SlideWindow();
		HandleDistance handleDistance = new HandleDistance();

		List<List<DataItem>> data_A = slideWindow.extractWindow(feature.getAbnormal(), trainpoints.get(0),
				config.getWindow_length());
		List<List<DataItem>> data_B = slideWindow.extractWindow(feature.getAbnormal(), trainpoints.get(1),
				config.getWindow_length());

		List<List<DataItem>> test_A = slideWindow.extractWindow(feature.getAbnormal(), testpoints.get(0),
				config.getWindow_length());
		List<List<DataItem>> test_B = slideWindow.extractWindow(feature.getAbnormal(), testpoints.get(1),
				config.getWindow_length());

		List<List<Double>> maps_A = new ArrayList<>();
		List<List<Double>> maps_B = new ArrayList<>();

		List<List<Double>> testmaps_A = new ArrayList<>();
		List<List<Double>> testmaps_B = new ArrayList<>();

		for (int i = 0; i < data_A.size(); i++) {
			List<Double> map = handelFeature.handlePaaFeature(data_A.get(i), config.getN_segment());
			maps_A.add(map);
		}

		for (int i = 0; i < data_B.size(); i++) {
			List<Double> map = handelFeature.handlePaaFeature(data_B.get(i), config.getN_segment());
			maps_B.add(map);
		}

		for (int i = 0; i < test_A.size(); i++) {
			List<Double> map = handelFeature.handlePaaFeature(test_A.get(i), config.getN_segment());
			testmaps_A.add(map);
		}

		for (int i = 0; i < test_B.size(); i++) {
			List<Double> map = handelFeature.handlePaaFeature(test_B.get(i), config.getN_segment());
			testmaps_B.add(map);
		}

		logger.info("Training Phase(Class A)");
		handleDistance.calAccuracy(maps_A, maps_B, maps_A, config.getK());

		logger.info("Training Phase(Class B)");
		handleDistance.calAccuracy(maps_B, maps_A, maps_B, config.getK());

		logger.info("Class A: ");
		handleDistance.calAccuracy(maps_A, maps_B, testmaps_A, config.getK());

		logger.info("Class B: ");
		handleDistance.calAccuracy(maps_B, maps_A, testmaps_B, config.getK());

		print(data_A, data_B, test_A, test_B);


	}

	public void paaclassifer(Feature feature, List<List<Long>> trainpoints, List<List<Long>> testpoints, int N_segment)
			throws IOException {
		Config config = new GetConfig().getConfig();
		HandelFeature handelFeature = new HandelFeature();
		SlideWindow slideWindow = new SlideWindow();
		HandleDistance handleDistance = new HandleDistance();

		List<List<DataItem>> data_A = slideWindow.extractWindow(feature.getAbnormal(), trainpoints.get(0),
				config.getWindow_length());
		List<List<DataItem>> data_B = slideWindow.extractWindow(feature.getAbnormal(), trainpoints.get(1),
				config.getWindow_length());

		List<List<DataItem>> test_A = slideWindow.extractWindow(feature.getAbnormal(), testpoints.get(0),
				config.getWindow_length());
		List<List<DataItem>> test_B = slideWindow.extractWindow(feature.getAbnormal(), testpoints.get(1),
				config.getWindow_length());

		List<List<Double>> maps_A = new ArrayList<>();
		List<List<Double>> maps_B = new ArrayList<>();

		List<List<Double>> testmaps_A = new ArrayList<>();
		List<List<Double>> testmaps_B = new ArrayList<>();

		for (int i = 0; i < data_A.size(); i++) {
			List<Double> map = handelFeature.handlePaaFeature(data_A.get(i), N_segment);
			maps_A.add(map);
		}

		for (int i = 0; i < data_B.size(); i++) {
			List<Double> map = handelFeature.handlePaaFeature(data_B.get(i), N_segment);
			maps_B.add(map);
		}

		for (int i = 0; i < test_A.size(); i++) {
			List<Double> map = handelFeature.handlePaaFeature(test_A.get(i), N_segment);
			testmaps_A.add(map);
		}

		for (int i = 0; i < test_B.size(); i++) {
			List<Double> map = handelFeature.handlePaaFeature(test_B.get(i), N_segment);
			testmaps_B.add(map);
		}

		logger.info("Training Phase(Class A)");
		handleDistance.calAccuracy(maps_A, maps_B, maps_A, config.getK());

		logger.info("Training Phase(Class B)");
		handleDistance.calAccuracy(maps_B, maps_A, maps_B, config.getK());

		logger.info("Class A: ");
		handleDistance.calAccuracy(maps_A, maps_B, testmaps_A, config.getK());

		logger.info("Class B: ");
		handleDistance.calAccuracy(maps_B, maps_A, testmaps_B, config.getK());

		print(data_A, data_B, test_A, test_B);


	}

	public void srdclassifer(Feature feature, List<List<Long>> trainpoints, List<List<Long>> testpoints, int N_segment)
			throws IOException {
		Config config = new GetConfig().getConfig();
		HandelFeature handelFeature = new HandelFeature();
		SlideWindow slideWindow = new SlideWindow();
		HandleDistance handleDistance = new HandleDistance();

		List<List<DataItem>> data_A = slideWindow.extractWindow(feature.getAbnormal(), trainpoints.get(0),
				config.getWindow_length());
		List<List<DataItem>> data_B = slideWindow.extractWindow(feature.getAbnormal(), trainpoints.get(1),
				config.getWindow_length());

		List<List<DataItem>> test_A = slideWindow.extractWindow(feature.getAbnormal(), testpoints.get(0),
				config.getWindow_length());
		List<List<DataItem>> test_B = slideWindow.extractWindow(feature.getAbnormal(), testpoints.get(1),
				config.getWindow_length());

		List<List<Double>> maps_A = new ArrayList<>();
		List<List<Double>> maps_B = new ArrayList<>();

		List<List<Double>> testmaps_A = new ArrayList<>();
		List<List<Double>> testmaps_B = new ArrayList<>();

		for (int i = 0; i < data_A.size(); i++) {
			List<Double> map = handelFeature.handleSrdFeature(data_A.get(i), N_segment);
			maps_A.add(map);
		}

		for (int i = 0; i < data_B.size(); i++) {
			List<Double> map = handelFeature.handleSrdFeature(data_B.get(i), N_segment);
			maps_B.add(map);
		}

		for (int i = 0; i < test_A.size(); i++) {
			List<Double> map = handelFeature.handleSrdFeature(test_A.get(i), N_segment);
			testmaps_A.add(map);
		}

		for (int i = 0; i < test_B.size(); i++) {
			List<Double> map = handelFeature.handleSrdFeature(test_B.get(i), N_segment);
			testmaps_B.add(map);
		}

		logger.info("Training Phase(Class A)");
		handleDistance.calAccuracy(maps_A, maps_B, maps_A, config.getK());

		logger.info("Training Phase(Class B)");
		handleDistance.calAccuracy(maps_B, maps_A, maps_B, config.getK());

		logger.info("Class A: ");
		handleDistance.calAccuracy(maps_A, maps_B, testmaps_A, config.getK());

		logger.info("Class B: ");
		handleDistance.calAccuracy(maps_B, maps_A, testmaps_B, config.getK());

		print(data_A, data_B, test_A, test_B);


	}




	public void print(List<List<DataItem>> data_A, List<List<DataItem>> data_B, List<List<DataItem>> test_A,
			List<List<DataItem>> test_B) throws IOException {

		Config config = new GetConfig().getConfig();
		ReadData readData = new ReadData();

		int[] datasets = new int[] { 103,148,183,260,293,424,456,511,721,850,878,952,1168,1468,1570,1788,1814,1874,1881,1896,2064,2067,2108,2240,2433,2469,2484,2664,2760,2814,2988,3011,3067,3130,3207,3275,3305,3306,3534,3539,3541,3551,3577,3606,3698,3718,3741,3844,3961,3982,4001,4022,4303,4304,4318,4564,4611,4677,4810,4907,4955,5042,5166,5481,5911,5943,5946,5947,5949,5988,6008,6064,6102,6118,6119,6121,6157,6283,6302,6328,6344,6385,6405,6435,6514,6582,6594,6604,6709,6768,6775,6779,6791,6799,6801,6862,6920,6946,6962,6971,6976,6998,7053,7128,7241,7265,7288,7310,7316,7369,7387,7414,7417,7474,7476,7520,7530,7533,7537,7541,7543,7553,7567,7570,7574,7664,7665,7715,7740,7765,7770,7794,7799,7888,7889,7899,7900,7903,7909,7910,7911,8076,8256,8273,8325,8330,8540,8572,8669,8832,8983,9145,9252,9307,9825,9831,10184,10269,10831,11063,11130,11136,11313,11345,11512,11518,11830,11868,11960,11962,12192,12515,12555,12708,12721,12764,12807,12825,12987,13014,13113,13665,13684,13845,13847,13866,13939,13962,14108,14197,14285,14330,14364,14663,14790,14798,14805,14930,15201,15313
 };

		List<DataItem> data_full = new ArrayList<>();

		for (int i = 0; i < datasets.length; i++) {
			String filePath = config.getPath() + "data\\" + datasets[i];
			List<DataItem> rawdata = readData.readDataFromFile(filePath);
			data_full.addAll(rawdata);
		}
		printPattern(data_full, data_A, data_B, config.getPath(), config.getWindow_length(), 0);
		printPattern(data_full, test_A, test_B, config.getPath(), config.getWindow_length(), 1);
	}

	public static void printPattern(List<DataItem> data, List<List<DataItem>> A, List<List<DataItem>> B, String path,
			long window_length, int flag) throws IOException {
		BinarySearch binarySearch = new BinarySearch();
		WriteData writeData = new WriteData();
		List<List<DataItem>> posi = new ArrayList<>();
		List<List<DataItem>> nega = new ArrayList<>();
		for (List<DataItem> window : A) {

			long mid = 0;
			double max = 0;
			for (DataItem di : window) {
				if (di.getValue() > max) {
					mid = di.getTimestamp();
					max = di.getValue();
				}
			}

			long begin = mid - window_length / 2;
			int begin_index = binarySearch.binarySearch(data, begin, 1);
			long end = mid + window_length / 2;
			int end_index = binarySearch.binarySearch(data, end, 0);

			posi.add(data.subList(begin_index, end_index + 1));

		}

		for (List<DataItem> window : B) {

			long mid = 0;
			double max = 0;
			for (DataItem di : window) {
				if (di.getValue() > max) {
					mid = di.getTimestamp();
					max = di.getValue();
				}
			}

			long begin = mid - window_length / 2;
			int begin_index = binarySearch.binarySearch(data, begin, 1);
			long end = mid + window_length / 2;
			int end_index = binarySearch.binarySearch(data, end, 0);

			nega.add(data.subList(begin_index, end_index + 1));

		}
		if (flag == 0) {
			writeData.writeDataUCRFormat(path + "dataset\\traindata", posi, nega);
			// writeData.writeDataFormat(path + "dataset\\posi\\posi", posi);
			// writeData.writeDataFormat(path + "dataset\\nega\\nega", nega);
		} else {
			writeData.writeDataUCRFormat(path + "dataset\\testdata", posi, nega);
		}

	}
}
